#include "iuPacketARP.hpp"
#include <arpa/inet.h>

/**
 * @brief Initialise le paquet ARP
 */
iuPacketARP::iuPacketARP()
{
   m_type = ARP_REQUEST;
}

/**
 * @brief Calcule la longueur du paquet ARP. Lorsque fromBuffer() est appelee, le buffer
 * passe en parametre devra avoir au moins cette taille
 * @return Renvoie la longueur du paquet ARP
 */
uint16_t iuPacketARP::getBufferLen() const
{
   uint16_t len;
   
   //Somme de la taille des differents champs du paquet ARP
   len = 2 + 2 + 1 + 1 + 2 + 6 + 4 + 6 + 4; 
   return len;
}

/**
 * @brief Lit le paquet ARP a partir d'un buffer
 * @param buffer le buffer ou le paquet ARP sera lu
 * @param len la longueur du paquet ARP a lire
 * @return Renvoie le nombre d'octets lus
 * @note On suppose que le paquet est bien forme
 */
uint16_t iuPacketARP::fromBuffer(const char *buffer, uint16_t len)
{
   const char *b = buffer;
   
   //Ignore le hardware-type, le protocol-type et la taille des adresses
   b += 6;

   //Lit le type du paquet (REQUEST ou REPLY)
   READ16(m_type, b);

   //Lit les adresses MAC et IP de l'emetteur
   b += m_srcMac.fromBuffer(b);
   b += m_srcIp.fromBuffer(b);

   //Lit les adresses MAC et IP du destinataire
   b += m_destMac.fromBuffer(b);
   b += m_destIp.fromBuffer(b);
   
   return (b - buffer);
}

/**
 * @brief Ecrit le paquet ARP dans le buffer. Le buffer devra avoir une taille d'au
 * moins getBufferLen() octets
 * @param buffer l'adresse du debut du buffer dans lequel sera ecrit le paquet ARP
 * @return Renvoie le nombre d'octets ecrits (== getBufferLen())
 */
uint16_t iuPacketARP::toBuffer(char *buffer) const
{
   char *b = buffer;
   
   //Ecrit le hardware-type et le protocol-type
   WRITE16(b, 1);
   WRITE16(b, 0x800);

   //Ecrit la taille des addresses MAC et IP
   *b = 6;
   b += 1;
   *b = 4;
   b += 1;

   //Ecrit le type du paquet (REQUEST ou REPLY)
   WRITE16(b, m_type);

   //Ecrit les adresses MAC et IP de l'emetteur
   b += m_srcMac.toBuffer(b);
   b += m_srcIp.toBuffer(b);

   //Ecrit les adresses MAC et IP du destinataire
   b += m_destMac.toBuffer(b);
   b += m_destIp.toBuffer(b);
   
   return (b - buffer);
}

/**
 * @brief Attribue le type du paquet ARP (REQUEST ou REPLY)
 * @param type le type a attribuer
 */
void iuPacketARP::setType(uint16_t type)
{
   m_type = type;
}

/**
 * @brief Recupere le type du paquet ARP (REQUEST ou REPLY)
 * @return Renvoie le type du paquet
 */
uint16_t iuPacketARP::getType() const
{
   return m_type;
}

/**
 * @brief Attribue l'adresse MAC de l'emetteur
 * @param address l'adresse a attribuer
 */
void iuPacketARP::setSourceMac(const iuMacAddress &address)
{
   m_srcMac = address;
}

/**
 * @brief Recupere l'adresse MAC de l'emetteur
 * @return Renvoie l'adresse
 */
const iuMacAddress &iuPacketARP::getSourceMac() const
{
   return m_srcMac;
}

/**
 * @brief Attribue l'adresse MAC du destinataire (ignore si la requete est de type REQUEST)
 * @param address l'adresse a attribuer
 */
void iuPacketARP::setDestinationMac(const iuMacAddress &address)
{
   m_destMac = address;
}

/**
 * @brief Recupere l'adresse MAC du destinataire
 * @return Renvoie l'adresse
 */
const iuMacAddress &iuPacketARP::getDestinationMac() const
{
   return m_destMac;
}

/**
 * @brief Attribue l'adresse IP de l'emetteur
 * @param address l'adresse a attribuer
 */
void iuPacketARP::setSourceIp(const iuIPAddress &address)
{
   m_srcIp = address;
}

/**
 * @brief Recupere l'adresse IP de l'emetteur
 * @return Renvoie l'adresse
 */
const iuIPAddress &iuPacketARP::getSourceIp() const
{
   return m_srcIp;
}

/**
 * @brief Attribue l'adresse IP du recepteur
 * @param address l'adresse a attribuer
 */
void iuPacketARP::setDestinationIp(const iuIPAddress &address)
{
   m_destIp = address;
}

/**
 * @brief Recupere l'adresse IP du recepteur
 * @return Renvoie l'adresse
 */
const iuIPAddress &iuPacketARP::getDestinationIp() const
{
   return m_destIp;
}
